package com.yeyks.service.impl;

import com.yeyks.base.PageInfo;
import com.yeyks.constant.MessageTemplate;
import com.yeyks.dal.dao.CouponInfoMapper;
import com.yeyks.dal.dao.UserCouponInfoMapper;
import com.yeyks.dal.domain.CouponInfo;
import com.yeyks.dal.domain.MessageNotice;
import com.yeyks.dal.domain.UserCouponInfo;
import com.yeyks.dal.domain.UserInfo;
import com.yeyks.dto.UserCouponInfoDTO;
import com.yeyks.dto.UserCouponResult;
import com.yeyks.exception.ServiceException;
import com.yeyks.model.CouponConst;
import com.yeyks.service.MessageNoticeService;
import com.yeyks.service.MessageNoticeTemplateService;
import com.yeyks.service.UserCouponService;
import com.yeyks.util.DateUtils;
import com.yeyks.base.PageInfo;
import com.yeyks.dal.dao.CouponInfoMapper;
import com.yeyks.dal.dao.UserCouponInfoMapper;
import com.yeyks.service.UserCouponService;
import com.yeyks.util.DateUtils;
import com.yeyks.util.FormatUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author fuchangshuai
 * @date 2019/2/28 10:03 AM
 */
@Slf4j
@Service
public class UserCouponServiceImpl implements UserCouponService {
    @Autowired
    private UserCouponInfoMapper userCouponInfoMapper;

    @Autowired
    private CouponInfoMapper couponInfoMapper;
    @Autowired
    private MessageNoticeService noticeService;
    @Autowired
    private MessageNoticeTemplateService templateService;

    /**
     * 共享读写锁
     */
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 根据一定条件查询当前用户的优惠券
     *
     * @param id
     * @param useStatus 是否已经使用, 默认1未使用，2已使用，3已过期
     * @param price 满减价格
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Map<String, Object> selectUserCouponList(Integer id, Integer useStatus, Integer price, Integer pageNum, Integer pageSize) {
        PageInfo pageInfo = PageInfo.of(pageNum, pageSize);
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("useStatus", useStatus);
        map.put("price", price);
        map.put("offset", pageInfo.getOffset());
        map.put("limit", pageInfo.getLimit());
        List<UserCouponResult> userCouponResults = userCouponInfoMapper.selectUserCouponList(map);
        Long count = userCouponInfoMapper.selectUserCouponListCountV2(map);
        map.clear();
        map.put("list", disposeResult(userCouponResults));
        map.put("count", count);
        return map;
    }

    private List<UserCouponResult> disposeResult(List<UserCouponResult> userCouponResults) {
        for (UserCouponResult userCouponResult : userCouponResults) {
            if (userCouponResult.getType() != null) {
                if (userCouponResult.getType().equals(CouponConst.recommend)
                        || userCouponResult.getType().equals(CouponConst.free)) {
                    userCouponResult.setPrice(userCouponResult.getCoupon_value());
                }
            }
        }
        return userCouponResults;
    }

    /**
     * 给用户发放两张新人红包券
     *
     * @param id
     */
    @Override
    @Transactional
    public Boolean createNewCoupon(Integer id) {
        //查询新人券(type=1 and price = 1000)
        CouponInfo couponInfo = couponInfoMapper.selectNewCoupon(1, 1000);
        if (couponInfo == null) {
            log.info("没有合适的10元新用户券");
            return false;
        }
        if (couponInfo.getRemainCount() == null || couponInfo.getRemainCount() <= 0) {
            log.info("10元新用户券剩余数量为空");
            return false;
        }
        //查询该用户是否已经领取过该券
        Integer count = userCouponInfoMapper.countOfUserIdCouponId(id, couponInfo.getId());
        if (count >= couponInfo.getCountPerUser()) {
            log.info("已领取过该券userId = {},couponId = {}", id, couponInfo.getId());
            return false;
        }
        UserCouponInfo userCouponInfo = getUserCouponInfo(id, couponInfo.getId(), couponInfo.getDuration());
        if (couponInfo.getCountPerUser() >= 2 && count == 0) {
            for (int i = 0; i < 2; i++) {
                userCouponInfoMapper.insertReturnId(userCouponInfo);
            }
            //新用户券通知记录
            registMessage(couponInfo.getPrice(), id, 2);
            updateCount(2, couponInfo);
        } else {
            userCouponInfoMapper.insertReturnId(userCouponInfo);
            //新用户券通知记录
            registMessage(couponInfo.getPrice(), id, 1);
            updateCount(1, couponInfo);
        }
        return true;
    }

    private void registMessage(Integer price, Integer userId, Integer count) {
        try {
            String amount = FormatUtils.fenToYuan(price);
            Map<String, Object> params = new HashMap<>();
            params.put("amount", amount);
            params.put("count", count);
            Map<String, String> map = templateService.commonValue(params, MessageTemplate.REGIST_COUPON);
            noticeService.activieyCreateAndSave(map, userId, MessageNotice.Type.activity_coupon.value());
        } catch (Exception e) {
            log.error("注册消息写入异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    /**
     * 通过count，减少券的剩余数，并增加券的领取数
     * @param count 领取的数量
     * @param couponInfo
     * @return
     */
    public Integer updateCount(Integer count, CouponInfo couponInfo) {
        Integer totalCount = couponInfo.getCount();
        if (totalCount == null || totalCount <= 0) {
            log.info("10元新用户券总数为空");
            return 0;
        }
        Integer getCount = couponInfo.getGetCount();
        Integer remainCount;
        getCount += count;
        if (totalCount < getCount) {
            log.info("10元新用户券已领取数大于总数");
            return 0;
        }
        remainCount = totalCount - getCount;
        couponInfo.setGetCount(getCount);
        couponInfo.setRemainCount(remainCount);
        return couponInfoMapper.updateByPrimaryKey(couponInfo);
    }

    /**
     * 修改券的使用条件
     *
     * @param couponId
     * @return
     */
    @Override
    public Integer updateUsed(Integer couponId) {
        return userCouponInfoMapper.updateUsed(couponId);
    }

    /**
     * 通过userCouponId修改优惠券的使用状态
     *
     * @param userCouponId
     * @param use
     * @return
     */
    @Override
    public Integer updateCouponUseById(Integer userCouponId, Boolean use) {
        return userCouponInfoMapper.updateCouponUseById(userCouponId, use);

    }

    /**
     * 通过券id和用户id查询该用户未使用的券
     *
     * @param couponId
     * @param id
     * @return
     */
    @Override
    public UserCouponInfo selectUserCoupon(Integer couponId, Integer id) {
        return userCouponInfoMapper.selectUserCoupon(couponId, id);
    }

    /**
     * 通过主键id查询用户券对象
     *
     * @param id
     * @return
     */
    @Override
    public UserCouponInfo selectUserCouponById(Integer id) {
        return userCouponInfoMapper.selectByPrimaryKey(id);
    }

    private UserCouponInfo getUserCouponInfo(Integer userId, Integer couponId, Integer duration) {
        UserCouponInfo userCouponInfo = new UserCouponInfo();
        userCouponInfo.setCouponId(couponId);
        userCouponInfo.setUserId(userId);
        userCouponInfo.setUsed(false);
        if (duration == null || duration == 0) {
            //180天
            duration = 180;
        }
        Date date = DateUtils.afterDaysToDate(new Date(), Long.valueOf(duration));
        userCouponInfo.setOverTime(date);
        return userCouponInfo;
    }
    /**
     * 用户领取券
     *
     * @param userId
     * @param couponId
     * @return
     */
    @Override
    public Boolean userGetCoupon(Integer userId, Integer couponId) {
        CouponInfo couponInfo = couponInfoMapper.selectByPrimaryKey(couponId);
        if (couponInfo == null) {
            log.info("没有找到券couponId = {}", couponId);
            throw new ServiceException("没有找到合适的券");
        }
        return getCoupon(couponInfo, userId);
    }

    /**
     * 用戶領取推广券
     *
     * @param userId
     * @param couponValue
     * @return
     */
    @Override
    public Boolean getRecommendCoupon(Integer userId, Integer couponValue) {
        CouponInfo couponInfo = null;
        if (couponValue == 20000) {
            couponInfo = couponInfoMapper.selectRecommendCoupon(CouponConst.free);
        } else {
            couponInfo = couponInfoMapper.selectRecommendCoupon(CouponConst.recommend);
        }
        if (couponInfo == null) {
            log.info("没有找到合适的推广券couponValue = {}", couponValue);
            throw new ServiceException("没有找到推广券");
        }
        return getRecommendCoupon(couponInfo, userId, couponValue);
    }

    /**
     * 用户领取鱼丸兑换券
     *
     * @param userId
     * @param couponId
     * @return
     */
    @Override
    public Boolean userGetFishBallCoupon(Integer userId, Integer couponId) {
        CouponInfo couponInfo = couponInfoMapper.selectByPrimaryKey(couponId);
        if (couponInfo == null) {
            log.info("没有找到券couponId = {}", couponId);
            throw new ServiceException("没有找到合适的券");
        }
        if (CouponConst.fishBall != couponInfo.getType()) {
            log.info("非鱼丸兑换券");
            throw new ServiceException("非鱼丸兑换券");
        }
        return getCoupon(couponInfo, userId);

    }

    /**
     * 获取推广充值获取的优惠券
     *
     * @param userInfo
     * @return
     */
    @Override
    public UserCouponInfoDTO selectNewCoupon(UserInfo userInfo) {
        UserCouponInfoDTO userCouponInfoDTO = new UserCouponInfoDTO();
        try {
            UserCouponInfo userCouponInfo = userCouponInfoMapper.selectByNewest(userInfo.getId());
            if (userCouponInfo == null || DateUtils.dateCompareDate(DateUtils.nowAfterMinuteToDate(-1), userCouponInfo.getGmtCreate())) {
                log.info("充值获取的优惠券为空userId = {}", userInfo.getId());
                return null;
            }
            userCouponInfoDTO.setOverTime(userCouponInfo.getOverTime());
            CouponInfo couponInfo = couponInfoMapper.selectByPrimaryKey(userCouponInfo.getCouponId());
            //TODO 跳过验证环节
            userCouponInfoDTO.setTitle(couponInfo.getTitle());
            userCouponInfoDTO.setPrice(userCouponInfo.getCouponValue());
            userCouponInfoDTO.setValidFee(couponInfo.getValidFee());
        } catch (Exception e) {
            log.error("获取推广充值获取的优惠券异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return userCouponInfoDTO;
    }

    private Boolean getCoupon(CouponInfo couponInfo, Integer userId) {
        if (DateUtils.dateCompareDate(new Date(), couponInfo.getValidEnd())) {
            log.info("券不在有效期");
            throw new ServiceException("券不在有效期");
        }
        if (!couponInfo.getStatus().equals(CouponConst.statusGetting)) {
            log.info("券不在发行期");
            throw new ServiceException("券不在发行期");
        }
        UserCouponInfo userCouponInfo = getUserCouponInfo(userId, couponInfo.getId(), couponInfo.getDuration());
        int res = userCouponInfoMapper.insertReturnId(userCouponInfo);
        if (res != 1) {
            log.info("增加券失败{}{}", couponInfo.getId(), userId);
            return false;
        }
        //减少券总数
        Integer remainCount = couponInfo.getRemainCount();
        remainCount = remainCount - 1 < 0 ? 0 : remainCount - 1;
        //已得到的券
        int getCount = couponInfo.getGetCount() == null ? 0 : couponInfo.getGetCount();
        couponInfo.setRemainCount(remainCount);
        couponInfo.setGetCount(getCount + 1);
        int coup = 0;
        try {
            lock.writeLock().lock();
            coup = couponInfoMapper.updateByPrimaryKey(couponInfo);
        } finally {
            lock.writeLock().unlock();
        }

        return coup == 1;
    }

    private Boolean getRecommendCoupon(CouponInfo couponInfo, Integer userId, Integer couponValue) {
        if (DateUtils.dateCompareDate(new Date(), couponInfo.getValidEnd())) {
            log.info("券不在有效期");
            throw new ServiceException("券不在有效期");
        }
        if (!couponInfo.getStatus().equals(CouponConst.statusGetting)) {
            log.info("券不在发行期");
            throw new ServiceException("券不在发行期");
        }
        if (couponInfo.getRemainCount() == null || couponInfo.getRemainCount() == 0) {
            log.info("券已领取完毕");
            throw new ServiceException("非常抱歉，该券已领取完毕");
        }
        UserCouponInfo userCouponInfo = recommendUserCouponInfo(userId, couponInfo.getId(), couponInfo.getDuration(), couponValue);
        int res = userCouponInfoMapper.insertReturnId(userCouponInfo);
        if (res != 1) {
            log.info("增加券失败{}{}", couponInfo.getId(), userId);
            return false;
        }
        //减少券总数
        Integer remainCount = couponInfo.getRemainCount();
        remainCount = remainCount - 1 < 0 ? 0 : remainCount - 1;
        //已得到的券
        int getCount = couponInfo.getGetCount() == null ? 0 : couponInfo.getGetCount();
        couponInfo.setRemainCount(remainCount);
        couponInfo.setGetCount(getCount + 1);
        int coup = couponInfoMapper.updateByPrimaryKey(couponInfo);
        return coup == 1;
    }

    private UserCouponInfo recommendUserCouponInfo(Integer userId, Integer couponId, Integer duration, Integer couponValue) {
        UserCouponInfo userCouponInfo = new UserCouponInfo();
        userCouponInfo.setCouponValue(couponValue);
        userCouponInfo.setCouponId(couponId);
        userCouponInfo.setUserId(userId);
        userCouponInfo.setUsed(false);
        if (duration == null || duration == 0) {
            //180天
            duration = 180;
        }
        Date date = DateUtils.afterDaysToDate(new Date(), Long.valueOf(duration));
        userCouponInfo.setOverTime(date);
        return userCouponInfo;
    }

}
